#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <fstream>
#include "Common.hpp"
#include "Log.hpp"
#include "Session.hpp"


const std::string Sep = "\r\n";
const std::string LineSep = " ";
const std::string HeaderLineSep = ": ";
const std::string BlankLine = Sep;
const std::string defaulthomepage = "wwwroot";
const std::string http_version = "HTTP/1.0";
const std::string page404 = "wwwroot/404.html";
const std::string firstpage = "index.html";

using namespace LogModule;

// B/S
class HttpRequest
{
public:
    HttpRequest(){};
    ~HttpRequest(){};

    bool IsHasArgs()
    {
        return _isexec;
    }

    // GET / HTTP/1.1
    // Host: 139.9.35.191:8080
    // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0
    // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    // Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
    // Accept-Encoding: gzip, deflate
    // Connection: keep-alive
    // Upgrade-Insecure-Requests: 1
    // Priority: u=0, i
    // 
    bool ParseHeaderKV()
    {
        std::string key, value;
        //std::cout << "####################" << std::endl;
        for(auto &header: _req_header)
        {
            // Host: 139.9.35.191:8080
            //std::cout << header << std::endl;
            if(SpiltString(header, HeaderLineSep, &key, &value))
            {
                _headerkv.insert(std::make_pair(key, value));
            }
        }
        //std::cout << "####################" << std::endl;

        return true;
    }

    bool ParseHeader(std::string &request_str)
    {
        std::string line;
        while(true)
        {
            bool ret = ParseOneLine(request_str, &line, Sep);
            if (ret && !line.empty())
            {
                _req_header.push_back(line);
            }
            else if (ret && line.empty())
            {
                _blank_line = Sep;
                break;
            }
            else
            {
                return false;
            }
        }
        ParseHeaderKV();
        return true;
    }

    void PraseCookie()
    {
        // 1. 从请求头中查找cookie
        // 写入：Set-Cookie: sessionid=1234; 提交： Cookie: sessionid=1234
        std::string prefix = "Cookie";
        for(auto &cookie: _headerkv)
        {
            if(cookie.first == prefix)
            {
                _cookies.emplace_back(cookie.second);
                LOG(LogLevel::DEBUG) << "cookie: " << cookie.second;
            }

        }
        
        // 2. 查找sessionid
        prefix = "sessionid=";
        for(auto &cookie : _cookies)
        {
            if (strncmp(cookie.c_str(), prefix.c_str(), prefix.size()) == 0)
            {
                _sessionid = cookie.substr(prefix.size()); // 截取"sessionid="后面的字符串"
                LOG(LogLevel::DEBUG) << "sessionid: " << _sessionid;
            }
        }
    }

    void Deserialize(std::string &request_str)
    {
        if(ParseOneLine(request_str, &_req_line, Sep))
        {
            // 提取请求行中的详细字段
            ParseReqLine(_req_line, LineSep);
            //LOG(LogLevel::DEBUG) << "request line: " << _req_line;
            ParseHeader(request_str);
            PraseCookie();
            _body = request_str;

            // 分析请求中，是否含有参数...
            if(_method == "POST")
            {
                _isexec = true;
                _path = _uri; // TODO
                _args = _body;
            }
            else if (_method == "GET")
            {
                auto pos = _uri.find("?");
                if(pos != std::string::npos)
                {
                    _isexec = true;  // /login?name=admin&pwd=123456
                    _path = _uri.substr(0, pos);
                    _args = _uri.substr(pos + 1);
                }
            }

        }
    }

    std::string Get_Content(const std::string &path)
    {
        std::string content;
        std::ifstream in(path, std::ios::binary);
        if(!in.is_open()) return std::string();
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);

        content.resize(filesize);
        in.read((char*)content.c_str(), filesize);
        in.close();
        return content;

        // // 临时做法
        // std::string _content;
        // std::ifstream in(_uri);
        // if(!in.is_open()) 
        // {
        //     return std::string();
        // }
        // std::string line;
        // while(std::getline(in, line))
        // {
        //     _content += line;
        // }
        // in.close();
    }

    void Print()
    {
        std::cout << "_method: " << _method << std::endl;
        std::cout << "_uri: " << _uri << std::endl;
        std::cout << "_version: " << _version << std::endl;
        for(auto &kv: _headerkv)
        {
            std::cout << kv.first << " # " << kv.second << std::endl;
        }
        std::cout << "_blank_line: " << _blank_line << std::endl;
        std::cout << "_body: " << _body << std::endl;
    }

    void SetUri(const std::string &newuri)
    {
        _uri = newuri;
    }

    std::string Uri() const { return _uri; }
    std::string Path() const { return _path; }
    std::string Args() const { return _args; }
    std::string SessionId() const { return _sessionid; }

    std::string Suffix()
    {
        // _uri -> wwwroot/index.html wwroot/image/1.jpg wwwroot/login.html
        auto pos = _uri.rfind(".");
        if(pos == std::string::npos) 
            return std::string(".html");
        else
            return _uri.substr(pos);
        
    }

private:
    void ParseReqLine(std::string &req_line, const std::string sep)
    {
        std::stringstream ss(req_line);
        ss >> _method >> _uri >> _version;  
        //std::cout << "first Uri: " << _uri << std::endl; // 打印请求的uri
    }
 
private:
    std::string _req_line;
    std::vector<std::string> _req_header;
    std::string _blank_line;
    std::string _body;  // 内部可能包含参数

    // 再反序列化的过程中，细化我们解析出来的字段
    std::string _method;
    std::string _uri;  //用户需要的  /login.html || /login?xxxxx
    std::string _path;
    std::string _args;
    std::string _version;
    //std::unordered_map<std::string, std::string> _headerkv;
    std::unordered_multimap<std::string, std::string> _headerkv;
    bool _isexec = false;
    // cookie and sessionid
    std::vector<std::string> _cookies;
    std::string _sessionid;
};

const std::string cookie_key = "Set-Cookie";

class HttpResponse
{
private:
    std::string GetMonthName(int month)
    {
        std::vector<std::string> months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
        return months[month];
    }
    std::string GetWeekName(int day)
    {
        std::vector<std::string> weeks = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
        return weeks[day];
    }
    std::string ExpireTimeUseRfc1123(int seconds) // 秒级别的未来UTC时间
    {
        time_t timeout = time(nullptr) + seconds;
        struct tm *tm = gmtime(&timeout);  // 这里不能用localtime，因为localtime是本地时间，而我们需要的是UTC时间
        char timebuffer[1024];
        // 时间格式如：Sun, 06 Nov 1994 08:49:37 UTC
        snprintf(timebuffer, sizeof(timebuffer), "%s, %02d %s %04d %02d:%02d:%02d UTC", 
            GetWeekName(tm->tm_wday).c_str(), 
            tm->tm_mday, 
            GetMonthName(tm->tm_mon).c_str(), 
            tm->tm_year + 1900, 
            tm->tm_hour, 
            tm->tm_min, 
            tm->tm_sec
        );
        return timebuffer;
    }

public:
    HttpResponse() :_version(http_version), _blank_line(Sep)
    {};

    ~HttpResponse(){};

    void Bulid(HttpRequest &req)
    {
        // std::string uri = req.Uri();
        // if(uri.back() == '/')
        // {
        //     _status_code = 301;
        //     _status_desc = Code2Desc(_status_code); // 和状态码是强相关的！
        //     // SetHeader("Location", "https://www.qq.com/");
        //     SetHeader("Location", "http://139.9.35.191:8080/register.html");
        //     for (auto &kv : _header_kv)
        //     {
        //         _resp_header.push_back(kv.first + HeaderLineSep + kv.second);
        //     }
        //     LOG(LogLevel::DEBUG) << "-------客户端在请求: " << req.Uri();
        //     return;
        // }
        LOG(LogLevel::DEBUG) << "first Uri: " << req.Uri();
        std::string uri = defaulthomepage + req.Uri();  // wwwroot/  wwwroot/a/b
        //LOG(LogLevel::DEBUG) << "second Uri: " << uri;

        if(uri.back() == '/')
        {
            uri += firstpage;  // wwwroot/index.html
            req.SetUri(uri);
        }

        _content = req.Get_Content(uri);
        //std::cout << "first GetContent###########################" << std::endl;
        if(_content.empty())
        {
            //用户请求的资源不存在
            _status_code = 404;
            req.SetUri(page404);
            _content = req.Get_Content(page404);
            //std::cout << "second GetContent###########################" << std::endl;
        }
        else
        {
            _status_code = 200;
        }
        _status_desc = Code2Desc(_status_code); // 和状态码是强相关的！
        //LOG(LogLevel::DEBUG) << "four Uri: " << req.Uri();

        // 构建正文长度行
        if(!_content.empty())
        {
            SetHeader("Content-Length", std::to_string(_content.size()));
        }

        std::string mime_type = Suffix2Desc(req.Suffix());
        SetHeader("Content-Type", mime_type);
        _body = _content;
    }

    void SetCode(int code)
    {
        _status_code = code;
        _status_desc = Code2Desc(code);
    }

    void SetBody(const std::string &body)
    {
        _body = body;
    }

    void SetHeader(const std::string &key, const std::string &value)
    {
        _header_kv.insert(std::make_pair(key, value));
    }

    void SetHeaderFromVector(const std::string &key, const std::string &value)
    {
        std::string kv_str = key + HeaderLineSep + value;
        _resp_header.push_back(kv_str);
    }
 
    void Serialize(std::string *resp_str)
    {
        for(auto &kv: _header_kv)
        {
            std::string kv_str = kv.first + HeaderLineSep + kv.second;
            _resp_header.push_back(kv_str);
        }
        //SetHeaderFromVector(cookie_key, "username=zhangsan; expires=" + ExpireTimeUseRfc1123(60) + ";");
        //SetHeaderFromVector(cookie_key, "username=zhangsan; path=/a/b");

        //std::cout << "before Serialize# " << _content << std::endl;
        _resp_line = _version + LineSep + std::to_string(_status_code) + LineSep + _status_desc + Sep;
        //std::cout << "after Serialize# " << _body << std::endl;

        // 序列化
        *resp_str = _resp_line;
        for(auto & line: _resp_header)
        {
            *resp_str += (line + Sep);
            //std::cout << "header: " << line << std::endl;
        }
        //LOG(LogLevel::DEBUG) << "resp_line: " << "\n" << resp_str;
        *resp_str += _blank_line;
        *resp_str += _body;
    }

private:
    std::string Code2Desc(int code) 
    {
        switch(code)
        {
            case 200:
                return "OK";
            case 301:
                return "Moved Permanently";
            case 302:
                return "Found";
            case 404:
                return "Not Found";
            default:
                return std::string();
        }
    }

    std::string Suffix2Desc(const std::string &suffix)
    {
        if(suffix == ".html")
            return "text/html";
        else if(suffix == ".jpg" || suffix == ".jpeg")
            return "image/jpeg";
        else if(suffix == ".png")
            return "image/png";
        else if(suffix == ".gif")
            return "image/gif";
        else
            return "text/html";
    }

private:
    // 必备的要素
    std::string _version;
    int _status_code;
    std::string _status_desc;
    std::string _content;
    //std::unordered_map<std::string, std::string> _header_kv;
    std::unordered_multimap<std::string, std::string> _header_kv;

    // 最终要这4部分，构成应答
    std::string _resp_line;
    std::vector<std::string> _resp_header;
    std::string _blank_line;
    std::string _body;

};